home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiniExamples / AppKit / ZooView / SideSplitView.m < prev    next >
Text File  |  1995-06-12  |  6KB  |  245 lines

  1. /* 
  2.  * SideSplitView.m
  3.  *
  4.  * Purpose:
  5.  *        This object implements a split view which divides a view into two
  6.  *        side by side areas. These areas are intended to be filled by subviews.
  7.  *        The user can then change the porportion of the subviews to one
  8.  *        another. The purpose is to provide developers with an alternative to
  9.  *        NXSplitView.
  10.  *
  11.  * You may freely copy, distribute, and reuse the code in this example.
  12.  * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  13.  * fitness for any particular use.
  14.  *
  15.  * Written by: Mary McNabb
  16.  * Created: Apr 91
  17.  *
  18.  */
  19.  
  20. #import "SideSplitView.h"
  21. #import <dpsclient/psops.h>
  22. #import <dpsclient/wraps.h>
  23. #import <math.h>
  24. #import <libc.h>
  25.  
  26. #define eventMask NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK
  27.  
  28. #define DIVIDERWIDTH 8.0        /* the divider is 8 pixels wide. */
  29. #define HALFWIDTH 4.0
  30.  
  31. static NXRect   dimpleRect = {{3.0, 5.0}, {8.0, 7.0}};
  32.  
  33. /* Retrace is 1/67 of sec * 10^6 micro secs per second */
  34. #define RETRACE    (1000000.0/67.0)  /* vertical retrace period in micro secs */
  35.  
  36. @implementation SideSplitView
  37.  
  38. /*
  39.  * initialize the split view. also initialize the size of the divider
  40.  */
  41. - initFrame:(NXRect *) theRect
  42. {
  43.     NXSize    dimpleSize;
  44.     
  45.     srandom(time(0));        /* initialize random number generator */
  46.     [super initFrame:theRect];
  47.     [self setAutoresizeSubviews:YES];
  48.     dimple = [NXImage findImageNamed:"Dimple"];
  49.     [dimple getSize:&dimpleSize];
  50.     
  51.     dimpleHalfHeight = floor(dimpleSize.height / 2.0);
  52.  
  53.     dividerRect.origin.x = 0.0;
  54.     dividerRect.origin.y = bounds.origin.y;
  55.     dividerRect.size.height = bounds.size.height;
  56.     dividerRect.size.width = dimpleSize.width + 3.0;
  57.     
  58.     minX = 0.0;
  59.  
  60.     return self;
  61. }
  62.  
  63. /*
  64.  * initialize the subviews of the split view.
  65.  */
  66. - initViews    
  67. {
  68.     [window disableFlushWindow];
  69.     [self adjustSubviews];            /* just in case we were sloppy in IB */
  70.     [window reenableFlushWindow];
  71.     [window flushWindow];
  72.     [self display];
  73.     return self;
  74. }
  75.  
  76. /*
  77.  * take advantage of IB. Use these set methods to initialize the subviews
  78.  */
  79. - setLeftView:(id)newView
  80. {
  81.     NXRect leftViewFrame;
  82.     
  83.     leftView = newView;
  84.     [leftView setAutosizing:NX_WIDTHSIZABLE|
  85.         NX_HEIGHTSIZABLE|NX_MAXXMARGINSIZABLE];
  86.             
  87.     [leftView getFrame:&leftViewFrame];
  88.     dividerRect.origin.x = leftViewFrame.size.width;
  89.     
  90.     [self addSubview:leftView];
  91.     return self;
  92. }
  93.  
  94. /*
  95.  * don't bother with the size and origin of the view as it gets completely reset in
  96.  * adjustSubviews
  97.  */
  98. - setRightView:(id)newView
  99. {
  100.     rightView = newView;
  101.     
  102.     [rightView setAutosizing:NX_WIDTHSIZABLE|
  103.         NX_HEIGHTSIZABLE|NX_MINXMARGINSIZABLE];
  104.     [self addSubview:rightView];
  105.     return self;
  106. }
  107.  
  108. - (BOOL)acceptsFirstMouse
  109. {
  110.     return YES;
  111. }
  112.  
  113. /*
  114.  * The side split view consists of a light gray background, and a dimple.
  115.  * Relies on the subviews to draw bevels, etc.
  116.  */
  117. - drawSelf:(const NXRect *)r :(int)c
  118. {
  119.     NXPoint dimplePoint;
  120.  
  121.     PSsetgray(NX_LTGRAY);
  122.     NXRectFill(&bounds);
  123.  
  124.     dimplePoint.x = dividerRect.origin.x + 1.0;
  125.     dimplePoint.y = floor(dividerRect.origin.y +
  126.                   dividerRect.size.height / 2.0 - dimpleHalfHeight);
  127.  
  128.     [dimple composite:NX_SOVER toPoint:&dimplePoint];
  129.  
  130.     return self;
  131. }
  132.  
  133. /*
  134.  * Controls the movement of the divider as the user slides it with the mouse
  135.  */
  136. - mouseDown:(NXEvent *) theEvent
  137. {
  138.     NXPoint localPoint = theEvent->location;
  139.     NXEvent *nextEvent;
  140.     NXCoord lastX=0.0;
  141.     int oldMask;
  142.  
  143.     [self convertPoint:&localPoint fromView:nil];
  144.     if (!NXMouseInRect(&localPoint, ÷rRect, NO))
  145.         return self;
  146.     oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
  147.  
  148.         /* We've gotten a mouse down on the divider, so go ahead and draw the slider now */
  149.     [self lockFocus];
  150.     PSsetinstance(YES);
  151.     PSsetgray(.50);
  152.     PSsetalpha(0.3333);
  153.     PScompositerect(localPoint.x-HALFWIDTH, dividerRect.origin.y,
  154.         DIVIDERWIDTH, dividerRect.size.height, NX_COPY);
  155.     
  156.         /* while the user is dragging composite a new slider in new postion -- watching for
  157.          * boundary conditions. Exit loop on mouse up.
  158.          */
  159.      do {
  160.         nextEvent = [NXApp getNextEvent:eventMask];
  161.         localPoint = nextEvent->location;
  162.         [self convertPoint:&localPoint fromView:nil];
  163.         if (localPoint.x < minX) localPoint.x = minX;
  164.         if (localPoint.x > maxX) localPoint.x = maxX;
  165.         if (localPoint.x != lastX) {
  166.             /* wait some random amount of time within retrace period. */
  167.             usleep((random() % (int)RETRACE));
  168.             PSnewinstance();
  169.             PScompositerect(localPoint.x-HALFWIDTH, dividerRect.origin.y,
  170.                 DIVIDERWIDTH, dividerRect.size.height, NX_COPY);
  171.             lastX = localPoint.x;
  172.         }
  173.     } while (nextEvent->type != NX_MOUSEUP);
  174.  
  175.         /* User is done dragging. Move the divider to new location
  176.          */    
  177.     dividerRect.origin.x = localPoint.x - HALFWIDTH;
  178.     PSsetinstance(NO);
  179.     [self unlockFocus];
  180.     [self adjustSubviews];
  181.     [self display];
  182.     [window setEventMask:oldMask];
  183.     
  184.     return self;
  185. }
  186.  
  187. /*
  188.  * blits the dimple to the screen in the right spot
  189.  */
  190. - drawDimple
  191. {
  192.     NXPoint origin;
  193.     origin.x = dividerRect.origin.x;
  194.     origin.y = floor(dividerRect.origin.y + dividerRect.size.height/2.0 - dimpleRect.size.height/2.0);
  195.     [dimple composite:NX_COPY fromRect:&dimpleRect toPoint:&origin];
  196.     return self;
  197. }
  198.  
  199. /*
  200.  * modifies the size of the subviews after user has positioned the divider, or
  201.  * has resized the window.
  202.  * also used to initialize the sizes of the subviews.
  203.  */
  204. - adjustSubviews
  205. {
  206.     NXRect leftViewFrame, rightViewFrame;
  207.  
  208.         /* first the left one  */
  209.     [leftView getFrame:&leftViewFrame];
  210.     leftViewFrame.size.width = dividerRect.origin.x - leftViewFrame.origin.x;
  211.     leftViewFrame.size.height = bounds.size.height;
  212.     leftViewFrame.origin.x = bounds.origin.x;
  213.     leftViewFrame.origin.y = bounds.origin.y;
  214.     [leftView setFrame:&leftViewFrame];
  215.     [window invalidateCursorRectsForView:leftView];
  216.  
  217.         /* then the right one */
  218.     [rightView getFrame:&rightViewFrame];
  219.     rightViewFrame.origin.x = leftViewFrame.size.width + DIVIDERWIDTH;
  220.     rightViewFrame.origin.y = bounds.origin.y;
  221.     rightViewFrame.size.width = bounds.size.width - rightViewFrame.origin.x;
  222.     rightViewFrame.size.height = bounds.size.height;
  223.     [rightView setFrame:&rightViewFrame];
  224.     [window invalidateCursorRectsForView:rightView];
  225.     
  226.         /* update dividerRect in case of resize of window */
  227.     dividerRect.origin.x = leftViewFrame.size.width;
  228.     dividerRect.size.height = leftViewFrame.size.height;
  229.     dividerRect.origin.y = leftViewFrame.origin.y;
  230.     maxX = bounds.size.width - HALFWIDTH;
  231.     return self;
  232. }
  233.  
  234. /*
  235.  * called when the window gets resized
  236.  */
  237. - resizeSubviews:(const NXSize *)oldSize 
  238. {
  239.     [super resizeSubviews:oldSize];
  240.     [self adjustSubviews];
  241.     return self;
  242. }
  243.  
  244. @end
  245.